home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / _archvrs / unix / unzip51 / vms / vms.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-25  |  34.7 KB  |  1,440 lines

  1. /*************************************************************************
  2.  *                                                                       *
  3.  * Copyright (C) 1992 Igor Mandrichenko.                                 *
  4.  * Permission is granted to any individual or institution to use, copy,  *
  5.  * or redistribute this software so long as all of the original files    *
  6.  * are included unmodified, that it is not sold for profit, and that     *
  7.  * this copyright notice is retained.                                    *
  8.  *                                                                       *
  9.  *************************************************************************/
  10.  
  11. /*
  12.  *    vms.c  by Igor Mandrichenko
  13.  *    version 1.3
  14.  *
  15.  *    This module contains routines to extract VMS file attributes
  16.  *    from extra field and create file with these attributes.  This
  17.  *    source is mainly based on sources of file_io.c from UnZip 4.1
  18.  *    by Info-ZIP.  [Info-ZIP note:  very little of this code is from
  19.  *    file_io.c; it has virtually been written from the ground up.
  20.  *    Of the few lines which are from the older code, most are mine
  21.  *    (G. Roelofs) and I make no claims upon them.  On the contrary,
  22.  *    my/our thanks to Igor for his contributions!]
  23.  */
  24.  
  25. /*
  26.  *      Revision history:
  27.  *      1.0-1   Mandrichenko    16-feb-1992
  28.  *              Recognize -c option
  29.  *      1.0-2   Mandrichenko    17-feb-1992
  30.  *              Do not use ASYnchroneous mode.
  31.  *      1.0-3   Mandrichenko    2-mar-1992
  32.  *              Make code more standard
  33.  *              Use lrec instead of crec -- unzip4.2p does not provide
  34.  *              crec now.
  35.  *      1.1     Mandrichenko    5-mar-1992
  36.  *              Make use of asynchronous output.
  37.  *              Be ready to extract RMS blocks of invalid size (because diff
  38.  *              VMS version used to compress).
  39.  *      1.1-1   Mandrichenko    11-mar-1992
  40.  *              Use internal file attributes saved in pInfo to decide
  41.  *              if the file is text.  [GRR:  temporarily disabled, since
  42.  *              no way to override and force binary extraction]
  43.  *      1.1-2   Mandrichenko    13-mar-1992
  44.  *              Do not restore owner/protection info if -X not specified.
  45.  *      1.1-3   Mandrichenko    30-may-1992
  46.  *              Set revision date/time to creation date/time if none specified
  47.  *              Take quiet flag into account.
  48.  *      1.1-4   Cave Newt       14-jun-1992
  49.  *              Check zipfile for variable-length format (unzip and zipinfo).
  50.  *    1.2    Mandrichenko    21-jun-1992
  51.  *        Use deflation/inflation for compression of extra blocks
  52.  *        Free all allocated space
  53.  *    1.2-1    Mandrichenko    23-jun-1992
  54.  *        Interactively select an action when file exists
  55.  *    1.2-2    Mandrichenko    6-oct-1992
  56.  *        Restore protection even with no -X.
  57.  *    1.2-3    Cave Newt    17-oct-1992
  58.  *        Use ulg/ush/uch instead of ULONG/UWORD/byte; move return_VMS()
  59.  *        here from misc.c; replace return codes with PK_ macros
  60.  *    1.3    Mandrichenko    25-oct-1992
  61.  *        Extract "-V" saved files to screen; use mapattr() for non-VMS
  62.  *        protections
  63.  */
  64.  
  65. #ifdef VMS            /*      VMS only !      */
  66.  
  67. #ifndef SYI$_VERSION
  68. #define SYI$_VERSION 4096    /* VMS 5.4 definition */
  69. #endif
  70.  
  71. #ifndef VAXC
  72.                 /* This definition may be missed */
  73. struct XAB {
  74.     unsigned char xab$b_cod;
  75.     unsigned char xab$b_bln;
  76.     short int xabdef$$_fill_1;
  77.     char *xab$l_nxt;
  78. };
  79.  
  80. #endif
  81.  
  82. #include "unzip.h"
  83. #include <ctype.h>
  84. #include <descrip.h>
  85. #include <syidef.h>
  86.  
  87. #define ERR(s) !((s) & 1)
  88.  
  89. #define BUFS512 8192*2        /* Must be a multiple of 512 */
  90.  
  91. /*
  92. *   Local static storage
  93. */
  94. static struct FAB fileblk;
  95. static struct XABDAT dattim;
  96. static struct XABRDT rdt;
  97. static struct RAB rab;
  98.  
  99. static struct FAB *outfab = 0;
  100. static struct RAB *outrab = 0;
  101. static struct XABFHC *xabfhc = 0;
  102. static struct XABDAT *xabdat = 0;
  103. static struct XABRDT *xabrdt = 0;
  104. static struct XABPRO *xabpro = 0;
  105. static struct XABKEY *xabkey = 0;
  106. static struct XABALL *xaball = 0;
  107. struct XAB *first_xab = 0L, *last_xab = 0L;
  108.  
  109. static char query = 0;
  110. static int  text_output = 0,
  111.         raw_input,
  112.         hostnum;
  113.  
  114. static uch rfm;
  115.  
  116. static uch locbuf[BUFS512];
  117. static int loccnt = 0;
  118. static uch *locptr;
  119.  
  120. static int WriteBuffer();
  121. static int _flush_blocks();
  122. static int _flush_stream();
  123. static int _flush_varlen();
  124. static int get_vms_version();
  125. static int replace();
  126. static uch *extract_block();
  127. static void message();
  128. static void free_up();
  129.  
  130. struct bufdsc
  131. {
  132.     struct bufdsc *next;
  133.     uch *buf;
  134.     int bufcnt;
  135. };
  136.  
  137. static struct bufdsc b1, b2, *curbuf;
  138. static uch buf1[BUFS512], buf2[BUFS512];
  139.  
  140.  
  141. int check_format()
  142. {
  143.     int rtype;
  144.     struct FAB fab;
  145.  
  146.     fab = cc$rms_fab;
  147.     fab.fab$l_fna = zipfn;
  148.     fab.fab$b_fns = strlen(zipfn);
  149.     sys$open(&fab);
  150.     rtype = fab.fab$b_rfm;
  151.     sys$close(&fab);
  152.  
  153.     if (rtype == FAB$C_VAR || rtype == FAB$C_VFC)
  154.     {
  155.     fprintf(stderr,
  156.         "\n     Error:  zipfile is in variable-length record format.  Please\n\
  157.      run \"bilf l %s\" to convert the zipfile to stream-LF\n\
  158.      record format.  (Bilf.exe, bilf.c and make_bilf.com are included\n\
  159.      in the VMS UnZip source distribution.)\n\n", zipfn);
  160.     return PK_ERR;
  161.     }
  162.  
  163.     return PK_COOL;
  164. }
  165.  
  166.  
  167. #ifndef ZIPINFO
  168.  
  169. #define PRINTABLE_FORMAT(x)    ( (x) == FAB$C_VAR         \
  170.                 || (x) == FAB$C_STMLF        \
  171.                 || (x) == FAB$C_STMCR        \
  172.                 || (x) == FAB$C_STM        )
  173.  
  174. int create_output_file()
  175. {
  176.     int ierr, yr, mo, dy, hh, mm, ss;
  177.     char timbuf[24];        /* length = first entry in "stupid" + 1 */
  178.     int attr_given;        /* =1 if VMS attributes are present in
  179.                 *     extra_field */
  180.  
  181.     rab = cc$rms_rab;        /* fill FAB & RAB with default values */
  182.     fileblk = cc$rms_fab;
  183.  
  184.     text_output = aflag || cflag;    /* We should extract the file to text
  185.                         *  (variable-length) format */
  186.     hostnum = pInfo -> hostnum;
  187.  
  188.     if (raw_input = attr_given = find_vms_attrs())
  189.     {    /*
  190.      *   Save extracted FAB fields because sys$open changes them
  191.      */
  192.  
  193.     text_output = cflag;    /* Ignore -a when attributes saved */
  194.  
  195.     if (cflag)
  196.     {
  197.         if(!PRINTABLE_FORMAT(rfm=outfab->fab$b_rfm))
  198.         {    printf("[ File %s has illegal record format to put to screen ]\n",
  199.            filename);
  200.             free_up();
  201.         return PK_DISK;
  202.         }
  203.     }
  204.     }
  205.     else
  206.     {
  207.     outfab = &fileblk;
  208.     outfab->fab$l_xab = 0L;
  209.     rfm = FAB$C_STMLF;    /* Default, stream-LF format from VMS
  210.                 *   or UNIX */
  211.     if (text_output)
  212.     {   /* Default format for output text file */
  213.  
  214.         outfab->fab$b_rfm = FAB$C_VAR;    /* variable length records */
  215.         outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  216.     }
  217.     else
  218.     {   /* Default format for output binary file */
  219.  
  220.         outfab->fab$b_rfm = FAB$C_STMLF;    /* stream-LF record format */
  221.         outfab->fab$b_rat = FAB$M_CR;    /* carriage-return carriage ctrl */
  222.     }
  223.     }
  224.  
  225.     if (!cflag)    /* Redirect output */
  226.     outfab->fab$l_fna = filename;
  227.     else
  228.     outfab->fab$l_fna = "sys$output:";
  229.  
  230.     outfab->fab$b_fns = strlen(outfab->fab$l_fna);
  231.  
  232.     if ((!attr_given) || xabdat == 0 || xabrdt == 0)    /* Use date/time info
  233.                              *  from zipfile if
  234.                              *  no attributes given
  235.                              */
  236.     {
  237.     static char *month[] =
  238.         {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  239.          "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
  240.  
  241.     /*  fixed-length string descriptor: */
  242.     struct dsc$descriptor stupid =
  243.         {23, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
  244.  
  245.     yr = ((lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
  246.     mo = ((lrec.last_mod_file_date >> 5) & 0x0f) - 1;
  247.     dy = (lrec.last_mod_file_date & 0x1f);
  248.     hh = (lrec.last_mod_file_time >> 11) & 0x1f;
  249.     mm = (lrec.last_mod_file_time >> 5) & 0x3f;
  250.     ss = (lrec.last_mod_file_time & 0x1f) * 2;
  251.  
  252.     dattim = cc$rms_xabdat;    /* fill XABs with default values */
  253.     rdt = cc$rms_xabrdt;
  254.     sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00", dy, month[mo], yr,
  255.         hh, mm, ss);
  256.     sys$bintim(&stupid, &dattim.xab$q_cdt);
  257.     memcpy(&rdt.xab$q_rdt, &dattim.xab$q_cdt, sizeof(rdt.xab$q_rdt));
  258.  
  259.     if ((!attr_given) || xabdat == 0L)
  260.     {
  261.         dattim.xab$l_nxt = outfab->fab$l_xab;
  262.         outfab->fab$l_xab = &dattim;
  263.     }
  264.     }
  265.  
  266.     outfab->fab$w_ifi = 0;    /* Clear IFI. It may be nonzero after ZIP */
  267.  
  268.     ierr = sys$create(outfab);
  269.     if (ierr == RMS$_FEX)
  270.     ierr = replace();
  271.  
  272.     if (ierr == 0)        /* Canceled */
  273.     return free_up(), 1;
  274.  
  275.     if (ERR(ierr))
  276.     {
  277.     char buf[256];
  278.  
  279.     sprintf(buf, "[ Cannot create output file %s ]\n", filename);
  280.     message(buf, ierr);
  281.     message("", outfab->fab$l_stv);
  282.     free_up();
  283.     return PK_WARN;
  284.     }
  285.  
  286.     if (!text_output)    /* Do not reopen text files and stdout
  287.             *  Just open them in right mode         */
  288.     {
  289.     /*
  290.     *       Reopen file for Block I/O with no XABs.
  291.     */
  292.     if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
  293.     {
  294. #ifdef DEBUG
  295.         message("[ create_output_file: sys$close failed ]\n", ierr);
  296.         message("", outfab->fab$l_stv);
  297. #endif
  298.         fprintf(stderr, "Can't create output file:  %s\n", filename);
  299.         free_up();
  300.         return PK_WARN;
  301.     }
  302.  
  303.  
  304.     outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;    /* Get ready for block
  305.                              * output */
  306.     outfab->fab$l_xab = 0L;    /* Unlink all XABs */
  307.  
  308.     if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
  309.     {
  310.         char buf[256];
  311.  
  312.         sprintf(buf, "[ Cannot open output file %s ]\n", filename);
  313.         message(buf, ierr);
  314.         message("", outfab->fab$l_stv);
  315.         free_up();
  316.         return PK_WARN;
  317.     }
  318.     }
  319.  
  320.     outrab = &rab;
  321.     rab.rab$l_fab = outfab;
  322.     if (!text_output)
  323.     {   rab.rab$l_rop |= RAB$M_BIO;
  324.         rab.rab$l_rop |= RAB$M_ASY;
  325.     }
  326.     rab.rab$b_rac = RAB$C_SEQ;
  327.  
  328.     if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
  329.     {
  330. #ifdef DEBUG
  331.     message("create_output_file: sys$connect failed.\n", ierr);
  332.     message("", outfab->fab$l_stv);
  333. #endif
  334.     fprintf(stderr, "Can't create output file:  %s\n", filename);
  335.     free_up();
  336.     return PK_WARN;
  337.     }
  338.  
  339.     locptr = &locbuf[0];
  340.     loccnt = 0;
  341.  
  342.     b1.buf = &buf1[0];
  343.     b1.bufcnt = 0;
  344.     b1.next = &b2;
  345.     b2.buf = &buf2[0];
  346.     b2.bufcnt = 0;
  347.     b2.next = &b1;
  348.     curbuf = &b1;
  349.  
  350.     return PK_COOL;
  351. }
  352.  
  353. static int replace()
  354. {                /*
  355.                 *    File exists. Inquire user about futher action.
  356.                 */
  357.     char answ[10];
  358.     struct NAM nam;
  359.     int ierr;
  360.  
  361.     if (query == 0)
  362.     {
  363.     do
  364.     {
  365.         fprintf(stderr,
  366.             "Replace %s : [o]verwrite, new [v]ersion or [c]ancel (O,V,C - all) ? ",
  367.             filename);
  368.         fflush(stderr);
  369.     } while (fgets(answ, 9, stderr) == NULL && !isalpha(answ[0])
  370.          && tolower(answ[0]) != 'o'
  371.          && tolower(answ[0]) != 'v'
  372.          && tolower(answ[0]) != 'c');
  373.  
  374.     if (isupper(answ[0]))
  375.         query = answ[0] = tolower(answ[0]);
  376.     }
  377.     else
  378.     answ[0] = query;
  379.  
  380.     switch (answ[0])
  381.     {
  382.     case 'c':
  383.         ierr = 0;
  384.         break;
  385.     case 'v':
  386.         nam = cc$rms_nam;
  387.         nam.nam$l_rsa = filename;
  388.         nam.nam$b_rss = FILNAMSIZ - 1;
  389.  
  390.         outfab->fab$l_fop |= FAB$M_MXV;
  391.         outfab->fab$l_nam = &nam;
  392.  
  393.         ierr = sys$create(outfab);
  394.         if (!ERR(ierr))
  395.         {
  396.         outfab->fab$l_nam = 0L;
  397.         filename[outfab->fab$b_fns = nam.nam$b_rsl] = 0;
  398.         }
  399.         break;
  400.     case 'o':
  401.         outfab->fab$l_fop |= FAB$M_SUP;
  402.         ierr = sys$create(outfab);
  403.         break;
  404.     }
  405.     return ierr;
  406. }
  407.  
  408. /*
  409. *   Extra record format
  410. *   ===================
  411. *   signature       (2 bytes)   = 'I','M'
  412. *   size            (2 bytes)
  413. *   block signature (4 bytes)
  414. *   flags           (2 bytes)
  415. *   uncomprssed size(2 bytes)
  416. *   reserved        (4 bytes)
  417. *   data            ((size-12) bytes)
  418. *   ....
  419. */
  420.  
  421. #define BC_MASK     07    /* 3 bits for compression type */
  422. #define BC_STORED    0    /* Stored */
  423. #define BC_00        1    /* 0byte -> 0bit compression */
  424. #define BC_DEFL        2    /* Deflated */
  425.  
  426. struct extra_block
  427. {
  428.     ush sig;            /* Extra field block header structure */
  429.     ush size;
  430.     ulg bid;
  431.     ush flags;
  432.     ush length;
  433.     ulg reserved;
  434.     uch body[1];
  435. };
  436.  
  437. /*
  438.  *   Extra field signature and block signatures
  439.  */
  440.  
  441. #define SIGNATURE "IM"
  442. #define FABL    (cc$rms_fab.fab$b_bln)
  443. #define RABL    (cc$rms_rab.rab$b_bln)
  444. #define XALLL   (cc$rms_xaball.xab$b_bln)
  445. #define XDATL   (cc$rms_xabdat.xab$b_bln)
  446. #define XFHCL   (cc$rms_xabfhc.xab$b_bln)
  447. #define XKEYL   (cc$rms_xabkey.xab$b_bln)
  448. #define XPROL   (cc$rms_xabpro.xab$b_bln)
  449. #define XRDTL   (cc$rms_xabrdt.xab$b_bln)
  450. #define XSUML   (cc$rms_xabsum.xab$b_bln)
  451. #define EXTBSL  4        /* Block signature length   */
  452. #define RESL    8        /* Rserved 8 bytes  */
  453. #define EXTHL   (4+EXTBSL)
  454. #define FABSIG  "VFAB"
  455. #define XALLSIG "VALL"
  456. #define XFHCSIG "VFHC"
  457. #define XDATSIG "VDAT"
  458. #define XRDTSIG "VRDT"
  459. #define XPROSIG "VPRO"
  460. #define XKEYSIG "VKEY"
  461. #define XNAMSIG "VNAM"
  462. #define VERSIG  "VMSV"
  463.  
  464.  
  465.  
  466. #define W(p)    (*(unsigned short*)(p))
  467. #define L(p)    (*(unsigned long*)(p))
  468. #define EQL_L(a,b)      ( L(a) == L(b) )
  469. #define EQL_W(a,b)      ( W(a) == W(b) )
  470.  
  471. /****************************************************************
  472.  * Function find_vms_attrs scans ZIP entry extra field if any   *
  473.  * and looks for VMS attribute records. Returns 0 if either no  *
  474.  * attributes found or no fab given.                            *
  475.  ****************************************************************/
  476. int find_vms_attrs()
  477. {
  478.     uch *scan = extra_field;
  479.     struct extra_block *blk;
  480.     int len;
  481.  
  482.     outfab = xabfhc = xabdat = xabrdt = xabpro = first_xab = last_xab = 0L;
  483.  
  484.     if (scan == NULL)
  485.     return PK_COOL;
  486.     len = lrec.extra_field_length;
  487.  
  488. #define LINK(p) {    /* Link xaballs and xabkeys into chain */    \
  489.                 if( first_xab == 0L )                   \
  490.                         first_xab = p;                  \
  491.                 if( last_xab != 0L )                    \
  492.                         last_xab -> xab$l_nxt = p;      \
  493.                 last_xab = p;                           \
  494.                 p -> xab$l_nxt = 0;                     \
  495.         }
  496.     /* End of macro LINK */
  497.  
  498.     while (len > 0)
  499.     {
  500.     blk = (struct block *) scan;
  501.     if (EQL_W(&blk->sig, SIGNATURE))
  502.     {
  503.         uch *block_id;
  504.  
  505.         block_id = &blk->bid;
  506.         if (EQL_L(block_id, FABSIG))
  507.         {
  508.         outfab = (struct FAB *) extract_block(blk, 0,
  509.                               &cc$rms_fab, FABL);
  510.         }
  511.         else if (EQL_L(block_id, XALLSIG))
  512.         {
  513.         xaball = (struct XABALL *) extract_block(blk, 0,
  514.                              &cc$rms_xaball, XALLL);
  515.         LINK(xaball);
  516.         }
  517.         else if (EQL_L(block_id, XKEYSIG))
  518.         {
  519.         xabkey = (struct XABKEY *) extract_block(blk, 0,
  520.                              &cc$rms_xabkey, XKEYL);
  521.         LINK(xabkey);
  522.         }
  523.         else if (EQL_L(block_id, XFHCSIG))
  524.         {
  525.         xabfhc = (struct XABFHC *) extract_block(blk, 0,
  526.                              &cc$rms_xabfhc, XFHCL);
  527.         }
  528.         else if (EQL_L(block_id, XDATSIG))
  529.         {
  530.         xabdat = (struct XABDAT *) extract_block(blk, 0,
  531.                              &cc$rms_xabdat, XDATL);
  532.         }
  533.         else if (EQL_L(block_id, XRDTSIG))
  534.         {
  535.         xabrdt = (struct XABRDT *) extract_block(blk, 0,
  536.                              &cc$rms_xabrdt, XRDTL);
  537.         }
  538.         else if (EQL_L(block_id, XPROSIG))
  539.         {
  540.         xabpro = (struct XABPRO *) extract_block(blk, 0,
  541.                              &cc$rms_xabpro, XPROL);
  542.         }
  543.         else if (EQL_L(block_id, VERSIG))
  544.         {
  545.         char verbuf[80];
  546.         int verlen = 0;
  547.         uch *vers;
  548.         char *m;
  549.  
  550.         get_vms_version(verbuf, 80);
  551.         vers = extract_block(blk, &verlen, 0, 0);
  552.         if ((m = strrchr(vers, '-')) != NULL)
  553.             *m = 0;    /* Cut out release number */
  554.         if (strcmp(verbuf, vers) && quietflg < 2)
  555.         {
  556.             printf("[ Warning: VMS version mismatch.");
  557.  
  558.             printf("   This version %s --", verbuf);
  559.             strncpy(verbuf, vers, verlen);
  560.             verbuf[verlen] = 0;
  561.             printf(" version made by %s ]\n", verbuf);
  562.         }
  563.         free(vers);
  564.         }
  565.         else if (quietflg < 2)
  566.         fprintf(stderr, "[ Warning: Unknown block signature %s ]\n",
  567.             block_id);
  568.     }
  569.     len -= blk->size + 4;
  570.     scan += blk->size + 4;
  571.     }
  572.  
  573.  
  574.     if (outfab != 0)
  575.     {    /* Do not link XABPRO,XABRDT now. Leave them for sys$close() */
  576.  
  577.     outfab->fab$l_xab = 0L;
  578.     if (xabfhc != 0L)
  579.     {
  580.         xabfhc->xab$l_nxt = outfab->fab$l_xab;
  581.         outfab->fab$l_xab = xabfhc;
  582.     }
  583.     if (xabdat != 0L)
  584.     {
  585.         xabdat->xab$l_nxt = outfab->fab$l_xab;
  586.         outfab->fab$l_xab = xabdat;
  587.     }
  588.     if (first_xab != 0L)    /* Link xaball,xabkey subchain */
  589.     {
  590.         last_xab->xab$l_nxt = outfab->fab$l_xab;
  591.         outfab->fab$l_xab = first_xab;
  592.     }
  593.     return 1;
  594.     }
  595.     else
  596.     return 0;
  597. }
  598.  
  599. static void free_up()
  600. {                /*
  601.                 *    Free up all allocated xabs
  602.                 */
  603.     if (xabdat != 0L) free(xabdat);
  604.     if (xabpro != 0L) free(xabpro);
  605.     if (xabrdt != 0L) free(xabrdt);
  606.     if (xabfhc != 0L) free(xabfhc);
  607.     while (first_xab != 0L)
  608.     {
  609.     struct XAB *x;
  610.  
  611.     x = first_xab->xab$l_nxt;
  612.     free(first_xab);
  613.     first_xab = x;
  614.     }
  615.     if (outfab != 0L && outfab != &fileblk)
  616.     free(outfab);
  617. }
  618.  
  619. static int get_vms_version(verbuf, len)
  620.     char *verbuf;
  621. int len;
  622. {
  623.     int i = SYI$_VERSION;
  624.     int verlen = 0;
  625.     struct dsc$descriptor version;
  626.     char *m;
  627.  
  628.     version.dsc$a_pointer = verbuf;
  629.     version.dsc$w_length = len - 1;
  630.     version.dsc$b_dtype = DSC$K_DTYPE_B;
  631.     version.dsc$b_class = DSC$K_CLASS_S;
  632.  
  633.     if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
  634.     return 0;
  635.  
  636.     /* Cut out trailing spaces "V5.4-3   " -> "V5.4-3" */
  637.     for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
  638.     --m;
  639.     *m = 0;
  640.  
  641.     /* Cut out release number "V5.4-3" -> "V5.4" */
  642.     if ((m = strrchr(verbuf, '-')) != NULL)
  643.     *m = 0;
  644.     return strlen(verbuf) + 1;    /* Transmit ending 0 too */
  645. }
  646.  
  647. /******************************
  648.  *   Function extract_block   *
  649.  ******************************/
  650. /*
  651.  * Extracts block from p. If resulting length is less then needed, fill
  652.  * extra space with corresponding bytes from 'init'.
  653.  * Currently understands 3 formats of block compression:
  654.  * - Simple storing
  655.  * - Compression of zero bytes to zero bits
  656.  * - Deflation. See memextract() from extract.c
  657.  */
  658. static uch *extract_block(p, retlen, init, needlen)
  659.     struct extra_block *p;
  660. int *retlen;
  661. uch *init;
  662. int needlen;
  663. {
  664.     uch *block;        /* Pointer to block allocated */
  665.     int cmptype;
  666.     int usiz, csiz, max;
  667.  
  668.     cmptype = p->flags & BC_MASK;
  669.     csiz = p->size - EXTBSL - RESL;
  670.     usiz = (cmptype == BC_STORED ? csiz : p->length);
  671.  
  672.     if (needlen == 0)
  673.     needlen = usiz;
  674.  
  675.     if (retlen)
  676.     *retlen = usiz;
  677.  
  678. #ifndef MAX
  679. #define MAX(a,b)    ( (a) > (b) ? (a) : (b) )
  680. #endif
  681.  
  682.     if ((block = (uch *) malloc(MAX(needlen, usiz))) == NULL)
  683.     return NULL;
  684.  
  685.     if (init && (usiz < needlen))
  686.     memcpy(block, init, needlen);
  687.  
  688.     switch (cmptype)
  689.     {
  690.     case BC_STORED:    /* The simplest case */
  691.         memcpy(block, &(p->body[0]), usiz);
  692.         break;
  693.     case BC_00:
  694.         decompress_bits(block, usiz, &(p->body[0]));
  695.         break;
  696.     case BC_DEFL:
  697.         memextract(block, usiz, &(p->body[0]), csiz);
  698.         break;
  699.     default:
  700.         free(block);
  701.         block = NULL;
  702.     }
  703.     return block;
  704. }
  705.  
  706. /*
  707.  *  Simple uncompression routine. The compression uses bit stream.
  708.  *  Compression scheme:
  709.  *
  710.  *  if(byte!=0)
  711.  *      putbit(1),putbyte(byte)
  712.  *  else
  713.  *      putbit(0)
  714.  */
  715. static void decompress_bits(outptr, needlen, bitptr)
  716.     uch *bitptr;
  717.  
  718. /* Pointer into compressed data */
  719. uch *outptr;            /* Pointer into output block */
  720. int needlen;            /* Size of uncompressed block */
  721. {
  722.     ulg bitbuf = 0;
  723.     int bitcnt = 0;
  724.  
  725. #define _FILL   if(bitcnt+8 <= 32)                      \
  726.                 {       bitbuf |= (*bitptr++) << bitcnt;\
  727.                         bitcnt += 8;                    \
  728.                 }
  729.  
  730.     while (needlen--)
  731.     {
  732.     if (bitcnt <= 0)
  733.         _FILL;
  734.  
  735.     if (bitbuf & 1)
  736.     {
  737.         bitbuf >>= 1;
  738.         if ((bitcnt -= 1) < 8)
  739.         _FILL;
  740.         *outptr++ = (uch) bitbuf;
  741.         bitcnt -= 8;
  742.         bitbuf >>= 8;
  743.     }
  744.     else
  745.     {
  746.         *outptr++ = 0;
  747.         bitcnt -= 1;
  748.         bitbuf >>= 1;
  749.     }
  750.     }
  751. }
  752.  
  753. /***************************/
  754. /*  Function FlushOutput() */
  755. /***************************/
  756.  
  757. int FlushOutput()
  758. {
  759.     if (mem_mode)
  760.     {                /* Hope mem_mode stays constant during
  761.                  * extraction */
  762.     int rc = FlushMemory();    /* For mem_extract() */
  763.  
  764.     outpos += outcnt;
  765.     outcnt = 0;
  766.     outptr = outbuf;
  767.     return rc;
  768.     }
  769.  
  770.     /* return PK-type error code */
  771.     /* flush contents of output buffer */
  772.     if (tflag)
  773.     {                /* Do not output. Update CRC only */
  774.     UpdateCRC(outbuf, outcnt);
  775.     outpos += outcnt;
  776.     outcnt = 0;
  777.     outptr = outbuf;
  778.     return PK_COOL;
  779.     }
  780.     else if( text_output )
  781.     switch(rfm)
  782.     {
  783.         case FAB$C_VAR:
  784.             return _flush_varlen(0);
  785.         case FAB$C_STM:
  786.         case FAB$C_STMCR:
  787.         case FAB$C_STMLF:
  788.             return _flush_stream(0);
  789.         default:
  790.             return _flush_blocks(0);
  791.     }
  792.     else
  793.     return _flush_blocks(0);
  794. }
  795.  
  796. static int _flush_blocks(final_flag)    /* Asynchronous version */
  797.     int final_flag;
  798. /* 1 if this is the final flushout */
  799. {
  800.     int round;
  801.     int rest;
  802.     int off = 0;
  803.     int out_count = outcnt;
  804.     int status;
  805.  
  806.     while (out_count > 0)
  807.     {
  808.     if (curbuf->bufcnt < BUFS512)
  809.     {
  810.         int ncpy;
  811.  
  812.         ncpy = out_count > (BUFS512 - curbuf->bufcnt) ?
  813.                 BUFS512 - curbuf->bufcnt :
  814.                 out_count;
  815.         memcpy(curbuf->buf + curbuf->bufcnt, outbuf + off, ncpy);
  816.         out_count -= ncpy;
  817.         curbuf->bufcnt += ncpy;
  818.         off += ncpy;
  819.     }
  820.     if (curbuf->bufcnt == BUFS512)
  821.     {
  822.         status = WriteBuffer(curbuf->buf, curbuf->bufcnt);
  823.         if (status)
  824.         return status;
  825.         curbuf = curbuf->next;
  826.         curbuf->bufcnt = 0;
  827.     }
  828.     }
  829.  
  830.     UpdateCRC(outbuf, outcnt);
  831.     outpos += outcnt;
  832.     outcnt = 0;
  833.     outptr = outbuf;
  834.  
  835.     return (final_flag && (curbuf->bufcnt > 0)) ?
  836.     WriteBuffer(curbuf->buf, curbuf->bufcnt) :
  837.     PK_COOL;
  838. }
  839.  
  840. static int _flush_varlen(final_flag)
  841. int final_flag;
  842. {
  843.     ush nneed;
  844.     ush reclen;
  845.     uch *inptr=outbuf;
  846.     int ocnt=outcnt;
  847.  
  848.     /*
  849.     *    Flush local buffer
  850.     */
  851.     if( loccnt > 0 )
  852.     {    reclen = *(ush*)locbuf;
  853.         if( (nneed = reclen + 2 - loccnt) > 0 )
  854.         {    if( nneed > ocnt )
  855.             {    if( ocnt+loccnt > BUFS512 )
  856.                 {    fprintf(stderr,"[ Record too long (%d bytes) ]\n",reclen );
  857.                     return PK_DISK;
  858.                 }
  859.                 memcpy(locbuf+loccnt,outbuf,ocnt);
  860.                 loccnt += ocnt;
  861.                 ocnt = 0;
  862.             }
  863.             else
  864.             {    memcpy(locbuf+loccnt,outbuf,nneed);
  865.                 loccnt += nneed;
  866.                 ocnt -= nneed;
  867.                 inptr += nneed;
  868.                 if( reclen & 1 )
  869.                 {    ocnt--;
  870.                     inptr++;
  871.                 }
  872.                 if( WriteRecord(locbuf+2,reclen) )
  873.                     return PK_DISK;
  874.                 loccnt = 0;
  875.             }
  876.         }
  877.         else
  878.         {    if(WriteRecord(locbuf+2,reclen))
  879.                 return PK_DISK;
  880.             loccnt -= reclen+2;
  881.         }
  882.     }
  883.     /*
  884.     *    Flush incoming records
  885.     */
  886.     while(ocnt > 0)
  887.     {    reclen = *(ush*)inptr;
  888.         if( reclen+2 <= ocnt )
  889.         {    if(WriteRecord(inptr+2,reclen))
  890.                 return PK_DISK;
  891.             ocnt -= 2+reclen;
  892.             inptr += 2+reclen;
  893.             if( reclen & 1)
  894.             {    --ocnt;
  895.                 ++inptr;
  896.             }
  897.         }
  898.         else
  899.         {    memcpy(locbuf,inptr,ocnt);
  900.             loccnt = ocnt;
  901.             ocnt = 0;
  902.         }
  903.                     
  904.     }
  905.     /*
  906.     *    Final flush rest of local buffer
  907.     */
  908.     if( final_flag && loccnt > 0 )
  909.     {    fprintf(stderr,
  910.             "[ Warning, incomplete record of length %d ]\n",
  911.             *(ush*)locbuf);
  912.         if( WriteRecord(locbuf+2,loccnt-2) )
  913.             return PK_DISK;
  914.     }
  915.     UpdateCRC(outbuf, outcnt);
  916.     outpos += outcnt;
  917.     outcnt = 0;
  918.     outptr = outbuf;
  919.     return PK_COOL;
  920. }
  921.  
  922. /*
  923. *   Routine _flush_stream breaks decompressed stream into records
  924. *   depending on format of the stream (fab->rfm, aflag etc) and puts
  925. *   out these records. It also handles CR LF sequences.
  926. *   Should be used when extracting *text* files.
  927. */
  928.  
  929. #define VT    0x0B
  930. #define FF    0x0C
  931.  
  932. /* GRR NOTES:  cannot depend on hostnum!  May have "flip'd" file or re-zipped
  933.  * a Unix file, etc.: */
  934.  
  935. /* The file is from MSDOS/OS2/NT -> handle CRLF as record end, throw out ^Z */
  936. #define ORG_DOS    (hostnum==FS_FAT_ || hostnum==FS_HPFS_ || hostnum==FS_NTFS_)
  937.  
  938. /* Record delimiters */
  939. #define RECORD_END(c,f)                                             \
  940. (        ( ORG_DOS || aflag ) && c==CTRLZ                    \
  941.     || ( f == FAB$C_STMLF && c==LF )                            \
  942.     || ( f == FAB$C_STMCR || ORG_DOS || aflag ) && c==CR        \
  943.     || ( f == FAB$C_STM && (c==CR || c==LF || c==FF || c==VT) ) \
  944. )
  945.  
  946. /* Record delimiters that must be put out */
  947. #define PRINT_SPEC(c)        \
  948. (        (c)==FF || (c)==VT    )
  949.  
  950. static int _flush_stream(final_flag)
  951.     int final_flag; /* 1 if this is the final flushout */
  952. {
  953.     int rest;
  954.     int end = 0, start = 0;
  955.     int off = 0;
  956.  
  957.     if (outcnt == 0 && loccnt == 0)
  958.     return PK_COOL;        /* Nothing to do ... */
  959.  
  960.     if (loccnt)
  961.     {    /* Find end of record partialy saved in locbuf */
  962.  
  963.     for (end = 0; end < outcnt && !RECORD_END(outbuf[end],rfm); )
  964.         ++end;
  965.  
  966.     if( end < outcnt && PRINT_SPEC(outbuf[end]) )    
  967.         ++end;  /* Print out VT and FF */
  968.  
  969.     if (end >= outcnt && !final_flag)
  970.     {
  971.         if (WriteRecord(locbuf, loccnt))
  972.         return PK_DISK;
  973.         fprintf(stderr, "[ Warning: Record too long (%d) ]\n",
  974.             outcnt + loccnt);
  975.         memcpy(locbuf, outbuf, outcnt);
  976.         locptr = &locbuf[loccnt = outcnt];
  977.     }
  978.     else
  979.     {
  980.         memcpy(locptr, outbuf, end);
  981.         if (WriteRecord(locbuf, loccnt + end))
  982.         return PK_DISK;
  983.         loccnt = 0;
  984.         locptr = &locbuf;
  985.     }
  986.  
  987.     start = end + 1;
  988.  
  989.     if (start < outcnt 
  990.        && ( rfm == FAB$C_STMCR || ORG_DOS || aflag )
  991.        && outbuf[end] == CR && outbuf[start] == LF)
  992.         ++start;
  993.     }
  994.  
  995.     do
  996.     {
  997.     if( cflag ) /* Skip CR's at the beginning of rec. */
  998.             while (start < outcnt && outbuf[start] == CR)    
  999.                 ++start;
  1000.  
  1001.     /* Find record end */
  1002.     for (end = start; end < outcnt && !RECORD_END(outbuf[end],rfm); )
  1003.         ++end;
  1004.  
  1005.     if( end < outcnt && PRINT_SPEC(outbuf[end]) )
  1006.         ++end;
  1007.  
  1008.     if (end < outcnt)
  1009.     {   /* Record end found, write the record */
  1010.         if (WriteRecord(outbuf + start, end - start))
  1011.         return PK_DISK;
  1012.         /* Shift to the begining of the next record */
  1013.         start = end + 1;
  1014.     }
  1015.  
  1016.     if (start < outcnt 
  1017.        && ( rfm == FAB$C_STMCR || ORG_DOS || aflag )
  1018.        && outbuf[end] == CR && outbuf[start] == LF)
  1019.         ++start;
  1020.  
  1021.     } while (start < outcnt && end < outcnt);
  1022.  
  1023.     rest = outcnt - start;
  1024.  
  1025.     if (rest > 0)
  1026.     if (final_flag)
  1027.     {
  1028.         /* This is a final flush. Put out all remaining in
  1029.         *  the buffer                               */
  1030.         if (loccnt && WriteRecord(locbuf, loccnt))
  1031.         return PK_DISK;
  1032.     }
  1033.     else
  1034.     {
  1035.         memcpy(locptr, outbuf + start, rest);
  1036.         locptr += rest;
  1037.         loccnt += rest;
  1038.     }
  1039.     UpdateCRC(outbuf, outcnt);
  1040.     outpos += outcnt;
  1041.     outcnt = 0;
  1042.     outptr = outbuf;
  1043.     return PK_COOL;
  1044. }
  1045.  
  1046. /***************************/
  1047. /*  Function WriteBuffer() */
  1048. /***************************/
  1049.  
  1050. static int WriteBuffer(buf, len)
  1051.     unsigned char *buf;
  1052. int len;
  1053. {
  1054.     int status;
  1055.  
  1056.     status = sys$wait(outrab);
  1057.     if (ERR(status))
  1058.     {
  1059.     message("[ WriteBuffer failed ]\n", status);
  1060.     message("", outrab->rab$l_stv);
  1061.     }
  1062.     outrab->rab$w_rsz = len;
  1063.     outrab->rab$l_rbf = buf;
  1064.  
  1065.     if (ERR(status = sys$write(outrab)))
  1066.     {
  1067.     message("[ WriteBuffer failed ]\n", status);
  1068.     message("", outrab->rab$l_stv);
  1069.     return PK_DISK;
  1070.     }
  1071.     return PK_COOL;
  1072. }
  1073.  
  1074. /***************************/
  1075. /*  Function WriteRecord() */
  1076. /***************************/
  1077.  
  1078. static int WriteRecord(rec, len)
  1079.     unsigned char *rec;
  1080. int len;
  1081. {
  1082.     int status;
  1083.  
  1084.     sys$wait(outrab);
  1085.     if (ERR(status))
  1086.     {
  1087.     message("[ WriteRecord failed ]\n", status);
  1088.     message("", outrab->rab$l_stv);
  1089.     }
  1090.     outrab->rab$w_rsz = len;
  1091.     outrab->rab$l_rbf = rec;
  1092.  
  1093.     if (ERR(status = sys$put(outrab)))
  1094.     {
  1095.     message("[ WriteRecord failed ]\n", status);
  1096.     message("", outrab->rab$l_stv);
  1097.     return PK_DISK;
  1098.     }
  1099.     return PK_COOL;
  1100. }
  1101.  
  1102. /********************************/
  1103. /*  Function CloseOutputFile()  */
  1104. /********************************/
  1105.  
  1106. int CloseOutputFile()
  1107. {
  1108.     int status;
  1109.     struct XABPRO pro;
  1110.  
  1111.     if( text_output )
  1112.     switch(rfm)
  1113.     {
  1114.         case FAB$C_VAR:
  1115.             status = _flush_varlen(1);
  1116.         case FAB$C_STM:
  1117.         case FAB$C_STMLF:
  1118.             status = _flush_stream(1);
  1119.         default:
  1120.             status = _flush_blocks(1);
  1121.     }
  1122.     else
  1123.     status = _flush_blocks(1);
  1124.  
  1125.     if(status)
  1126.     return PK_DISK;
  1127.  
  1128.     /* Link XABRDT,XABDAT and optionaly XABPRO */
  1129.     if (xabrdt != 0L)
  1130.     {
  1131.     xabrdt->xab$l_nxt = 0L;
  1132.     outfab->fab$l_xab = xabrdt;
  1133.     }
  1134.     else
  1135.     {
  1136.     rdt.xab$l_nxt = 0L;
  1137.     outfab->fab$l_xab = &rdt;
  1138.     }
  1139.     if (xabdat != 0L)
  1140.     {
  1141.     xabdat->xab$l_nxt = outfab->fab$l_xab;
  1142.     outfab->fab$l_xab = xabdat;
  1143.     }
  1144.  
  1145.     if( xabpro != 0L )
  1146.     {
  1147.     if( !secinf )
  1148.         xabpro->xab$l_uic = 0;    /* Use default (user's) uic */
  1149.     xabpro->xab$l_nxt = outfab->fab$l_xab;
  1150.     outfab->fab$l_xab = xabpro;
  1151.     }
  1152.     else
  1153.     {    pro = cc$rms_xabpro;
  1154.     pro.xab$w_pro = pInfo->file_attr;
  1155.     pro.xab$l_nxt = outfab->fab$l_xab;
  1156.     outfab->fab$l_xab = &pro;
  1157.     }
  1158.  
  1159.     sys$wait(outrab);
  1160.  
  1161.     status = sys$close(outfab);
  1162. #ifdef DEBUG
  1163.     if (ERR(status))
  1164.     {
  1165.     message("\r[ Warning: cannot set owner/protection/time attributes ]\n",
  1166.       status);
  1167.     message("", outfab->fab$l_stv);
  1168.     }
  1169. #endif
  1170.     free_up();
  1171. }
  1172.  
  1173. #ifdef DEBUG
  1174. dump_rms_block(p)
  1175.     unsigned char *p;
  1176. {
  1177.     unsigned char bid, len;
  1178.     int err;
  1179.     char *type;
  1180.     char buf[132];
  1181.     int i;
  1182.  
  1183.     err = 0;
  1184.     bid = p[0];
  1185.     len = p[1];
  1186.     switch (bid)
  1187.     {
  1188.     case FAB$C_BID:
  1189.         type = "FAB";
  1190.         break;
  1191.     case XAB$C_ALL:
  1192.         type = "xabALL";
  1193.         break;
  1194.     case XAB$C_KEY:
  1195.         type = "xabKEY";
  1196.         break;
  1197.     case XAB$C_DAT:
  1198.         type = "xabDAT";
  1199.         break;
  1200.     case XAB$C_RDT:
  1201.         type = "xabRDT";
  1202.         break;
  1203.     case XAB$C_FHC:
  1204.         type = "xabFHC";
  1205.         break;
  1206.     case XAB$C_PRO:
  1207.         type = "xabPRO";
  1208.         break;
  1209.     default:
  1210.         type = "Unknown";
  1211.         err = 1;
  1212.         break;
  1213.     }
  1214.     printf("Block @%08X of type %s (%d).", p, type, bid);
  1215.     if (err)
  1216.     {
  1217.     printf("\n");
  1218.     return;
  1219.     }
  1220.     printf(" Size = %d\n", len);
  1221.     printf(" Offset - Hex - Dec\n");
  1222.     for (i = 0; i < len; i += 8)
  1223.     {
  1224.     int j;
  1225.  
  1226.     printf("%3d - ", i);
  1227.     for (j = 0; j < 8; j++)
  1228.         if (i + j < len)
  1229.         printf("%02X ", p[i + j]);
  1230.         else
  1231.         printf("   ");
  1232.     printf(" - ");
  1233.     for (j = 0; j < 8; j++)
  1234.         if (i + j < len)
  1235.         printf("%03d ", p[i + j]);
  1236.         else
  1237.         printf("    ");
  1238.     printf("\n");
  1239.     }
  1240. }
  1241.  
  1242. #endif                /* DEBUG */
  1243.  
  1244. static void message(string, status)
  1245.     int status;
  1246. char *string;
  1247. {
  1248.     char msgbuf[256];
  1249.  
  1250.     $DESCRIPTOR(msgd, msgbuf);
  1251.     int msglen = 0;
  1252.  
  1253.     if (ERR(lib$sys_getmsg(&status, &msglen, &msgd, 0, 0)))
  1254.     fprintf(stderr, "%s[ VMS status = %d ]\n", string, status);
  1255.     else
  1256.     {
  1257.     msgbuf[msglen] = 0;
  1258.     fprintf(stderr, "%s[ %s ]\n", string, msgbuf);
  1259.     }
  1260. }
  1261.  
  1262.  
  1263.  
  1264. /****************************************
  1265. * File protection mapping routine
  1266. ****************************************/
  1267.  
  1268. static ulg unix_to_vms[8]={ /* Map from UNIX rwx to VMS rwed */
  1269.                 /* Note that unix w bit is mapped to VMS wd bits */
  1270.     XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE,    /* --- no access*/
  1271.     XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL,                  /* --x */
  1272.     XAB$M_NOREAD |                               XAB$M_NOEXE,    /* -w- */
  1273.     XAB$M_NOREAD,                                                /* -wx */
  1274.                    XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE,    /* r-- */
  1275.                    XAB$M_NOWRITE | XAB$M_NODEL,                  /* r-x */
  1276.                                                  XAB$M_NOEXE,    /* rw- */
  1277.     0                                                            /* rwx full access*/
  1278. };
  1279.  
  1280. #define SETDFPROT   /* We are using undocumented VMS System Service    */
  1281.             /* SYS$SETDFPROT here. If your version of VMS does    */
  1282.             /* not have that service, undef SETDFPROT.        */
  1283.             /* IM: Maybe it's better to put this to Makefile    */
  1284.             /* and DESCRIP.MMS */
  1285.  
  1286. int mapattr()
  1287. {
  1288.     ulg  tmp=crec.external_file_attributes, theprot;
  1289.     static ulg  defprot = -1L,
  1290.         sysdef,owndef,grpdef,wlddef;  /* Default protection fields */
  1291.  
  1292.  
  1293.     /* IM: The only field of XABPRO we need to set here is */
  1294.     /*     file protection, so we need not to change type */
  1295.     /*     of pInfo->file_attr. WORD is quite enough. */
  1296.  
  1297.     if( defprot == -1L )
  1298.     {
  1299.     /*
  1300.     * First time here -- Get user default settings
  1301.     */
  1302.  
  1303. #ifdef SETDFPROT    /* Undef this if linker cat't resolve SYS$SETDFPROT */
  1304.     defprot = 0L;
  1305.     if( !ERR(SYS$SETDFPROT(0,&defprot)) )
  1306.     {
  1307.         sysdef = defprot & ( (1L<<XAB$S_SYS)-1 ) << XAB$V_SYS;
  1308.         owndef = defprot & ( (1L<<XAB$S_OWN)-1 ) << XAB$V_OWN;
  1309.         grpdef = defprot & ( (1L<<XAB$S_GRP)-1 ) << XAB$V_GRP;
  1310.         wlddef = defprot & ( (1L<<XAB$S_WLD)-1 ) << XAB$V_WLD;
  1311.     }
  1312.     else
  1313.     {
  1314. #endif /* ?SETDFPROT */
  1315.         umask(defprot = umask(0));
  1316.         defprot = ~defprot;
  1317.         wlddef = unix_to_vms[defprot & 07] << XAB$V_WLD;
  1318.         grpdef = unix_to_vms[(defprot>>3) & 07] << XAB$V_GRP;
  1319.         owndef = unix_to_vms[(defprot>>6) & 07] << XAB$V_OWN;
  1320.         sysdef = owndef << (XAB$V_SYS - XAB$V_OWN);
  1321.         defprot = sysdef | owndef | grpdef | wlddef;
  1322. #ifdef SETDFPROT
  1323.     }
  1324. #endif    /* ?SETDFPROT */
  1325.     }
  1326.  
  1327.     switch (pInfo->hostnum) {
  1328.         case UNIX_:
  1329.         case VMS_:  /*IM: ??? Does VMS Zip store protection in UNIX format ?*/
  1330.                     /* GRR:  Yup.  Bad decision on my part... */
  1331.             tmp = (unsigned)(tmp >> 16);  /* drwxrwxrwx */
  1332.         theprot  = (unix_to_vms[tmp & 07] << XAB$V_WLD)
  1333.                  | (unix_to_vms[(tmp>>3) & 07] << XAB$V_GRP)
  1334.                  | (unix_to_vms[(tmp>>6) & 07] << XAB$V_OWN);
  1335.  
  1336.         if( tmp & 0x4000 )
  1337.             /* Directory -- set D bits */
  1338.         theprot |= (XAB$M_NODEL << XAB$V_SYS)
  1339.             | (XAB$M_NODEL << XAB$V_OWN)
  1340.             | (XAB$M_NODEL << XAB$V_GRP)
  1341.             | (XAB$M_NODEL << XAB$V_WLD);
  1342.         pInfo->file_attr = theprot;
  1343.         break;
  1344.  
  1345.         case AMIGA_:
  1346.             tmp = (unsigned)(tmp>>16 & 0x0f);   /* Amiga RWED bits */
  1347.             pInfo->file_attr = (tmp << XAB$V_OWN) | grpdef | sysdef | wlddef;
  1348.             break;
  1349.  
  1350.         /* all remaining cases:  expand MSDOS read-only bit into write perms */
  1351.         case FS_FAT_:
  1352.         case FS_HPFS_:
  1353.         case FS_NTFS_:
  1354.         case MAC_:
  1355.         case ATARI_:             /* (used to set = 0666) */
  1356.         case TOPS20_:
  1357.         default:
  1358.         theprot = defprot;
  1359.         if( tmp & 1 )   /* Test read-only bit */
  1360.         {    /* Bit is set -- set bits in all fields */
  1361.         tmp = XAB$M_NOWRITE | XAB$M_NODEL;
  1362.         theprot |= (tmp << XAB$V_SYS) | (tmp << XAB$V_OWN) |
  1363.                (tmp << XAB$V_GRP) | (tmp << XAB$V_WLD);
  1364.         }
  1365.             pInfo->file_attr = theprot;
  1366.             break;
  1367.     } /* end switch (host-OS-created-by) */
  1368.  
  1369.     return 0;
  1370.  
  1371. } /* end function mapattr() */
  1372.  
  1373. #endif                /* !ZIPINFO */
  1374.  
  1375.  
  1376.  
  1377. void return_VMS(zip_error)
  1378.     int zip_error;
  1379. {
  1380. #ifdef RETURN_CODES
  1381. /*---------------------------------------------------------------------------
  1382.     Do our own, explicit processing of error codes and print message, since
  1383.     VMS misinterprets return codes as rather obnoxious system errors ("access
  1384.     violation," for example).
  1385.   ---------------------------------------------------------------------------*/
  1386.  
  1387.     switch (zip_error) {
  1388.  
  1389.     case PK_COOL:
  1390.         break;   /* life is fine... */
  1391.     case PK_WARN:
  1392.         fprintf(stderr, "\n[return-code 1:  warning error \
  1393. (e.g., failed CRC or unknown compression method)]\n");
  1394.         break;
  1395.     case PK_ERR:
  1396.     case PK_BADERR:
  1397.         fprintf(stderr, "\n[return-code %d:  error in zipfile \
  1398. (e.g., can't find local file header sig)]\n",
  1399.                 zip_error);
  1400.         break;
  1401.     case PK_MEM:
  1402.     case PK_MEM2:
  1403.     case PK_MEM3:
  1404.     case PK_MEM4:
  1405.     case PK_MEM5:
  1406.         fprintf(stderr, "\n[return-code %d:  insufficient memory]\n",
  1407.           zip_error);
  1408.         break;
  1409.     case PK_NOZIP:
  1410.         fprintf(stderr, "\n[return-code 9:  zipfile not found]\n");
  1411.         break;
  1412.     case PK_PARAM:   /* the one that gives "access violation," I think */
  1413.         fprintf(stderr, "\n[return-code 10:  bad or illegal parameters \
  1414. specified on command line]\n");
  1415.         break;
  1416.     case PK_FIND:
  1417.         fprintf(stderr,
  1418.           "\n[return-code 11:  no files found to extract/view/etc.]\n");
  1419.         break;
  1420.     case PK_DISK:
  1421.         fprintf(stderr,
  1422.   "\n[return-code 50:  disk full (or otherwise unable to open output file)]\n");
  1423.         break;
  1424.     case PK_EOF:
  1425.         fprintf(stderr,
  1426.           "\n[return-code 51:  unexpected EOF in zipfile (i.e., truncated)]\n");
  1427.         break;
  1428.     default:
  1429.         fprintf(stderr, "\n[return-code %d:  unknown return-code (screw-up)]\n",
  1430.           zip_error);
  1431.         break;
  1432.     }
  1433. #endif /* RETURN_CODES */
  1434.  
  1435.     exit(0);   /* everything okey-dokey as far as VMS concerned */
  1436.  
  1437. } /* end function return_VMS() */
  1438.  
  1439. #endif                /* VMS */
  1440.